package com.soyea.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import com.soyea.beans.LogType;
import com.soyea.common.RequestHolder;
import com.soyea.dao.SysLogMapper;
import com.soyea.dao.SysRoleAclMapper;
import com.soyea.model.SysLogWithBLOBs;
import com.soyea.model.SysRoleAcl;
import com.soyea.util.IpUtil;
import com.soyea.util.JsonMapper;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * 角色 - 资源 service
 */
@Service
@Transactional
public class SysRoleAclService {

    @Autowired
    private SysRoleAclMapper sysRoleAclMapper;
    @Resource
    private SysLogMapper sysLogMapper;

    /**
     * 改变角色和资源的关系
     *
     * 思路
     * 先根据roleId查询出原来的权限id列表
     * 判断原来的权限id列表是否和要修改的权限id列表相同,判断方法:先判断size是否相同,若相同再判断里面元素是否都相同,通过set集合的removeAll方法
     *      如果remove后的集合为空,则说明元素完全相同,注意不能用containAll方法
     * 如果相同,则直接返回不修改,提高效率
     * 否则开始修改数据
     * 保存日志
     *
     * @param roleId
     * @param aclIdList
     */
    public void changeRoleAcls(Integer roleId, List<Integer> aclIdList) {
        //先查询出原来的权限列表
        List<Integer> originAclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(Lists.newArrayList(roleId));
        if (originAclIdList.size() == aclIdList.size()) {
            //判断是否和原来的一样,一样则直接返回不修改
            Set<Integer> originAclIdSet = Sets.newHashSet(originAclIdList);
            Set<Integer> aclIdSet = Sets.newHashSet(aclIdList);
            originAclIdSet.removeAll(aclIdSet);
            if (CollectionUtils.isEmpty(originAclIdSet)) {
                return;
            }
        }
        updateRoleAcls(roleId, aclIdList);
        saveRoleAclLog(roleId, originAclIdList, aclIdList);
    }

    /**
     * 修改角色和资源的关系
     *
     * 思路:
     * 先删除原来的表记录
     * 判断权限id列表是否为空,若为空,说明该角色将无任何权限,直接返回
     * 若不为空,则遍历权限id列表,补全SysRoleAcl属性,添加到集合中
     * 批量插入新的表记录
     *
     * @param roleId
     * @param aclIdList
     */
    private void updateRoleAcls(int roleId, List<Integer> aclIdList) {
        //先删除原来的表记录
        sysRoleAclMapper.deleteByRoleId(roleId);

        if (CollectionUtils.isEmpty(aclIdList)) {
            return;
        }
        List<SysRoleAcl> roleAclList = Lists.newArrayList();
        for(Integer aclId : aclIdList) {
            SysRoleAcl roleAcl = SysRoleAcl.builder().roleId(roleId).aclId(aclId).operator(RequestHolder.getCurrentUser().getUsername())
                    .operateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest())).operateTime(new Date()).build();
            roleAclList.add(roleAcl);
        }
        //再批量插入新的表记录
        sysRoleAclMapper.batchInsert(roleAclList);
    }

    private void saveRoleAclLog(int roleId, List<Integer> before, List<Integer> after) {
        SysLogWithBLOBs sysLog = new SysLogWithBLOBs();
        sysLog.setType(LogType.TYPE_ROLE_ACL);
        sysLog.setTargetId(roleId);
        sysLog.setOldValue(before == null ? "" : JsonMapper.obj2String(before));
        sysLog.setNewValue(after == null ? "" : JsonMapper.obj2String(after));
        sysLog.setOperator(RequestHolder.getCurrentUser().getUsername());
        sysLog.setOperateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest()));
        sysLog.setOperateTime(new Date());
        sysLog.setStatus(1);
        sysLogMapper.insertSelective(sysLog);
    }
}
